package com.sskj.camera.service.impl;

import com.sskj.camera.domain.Camera;
import com.sskj.camera.properties.SRSProperties;
import com.sskj.camera.service.ICameraService;
import com.sskj.camera.service.ICameraStreamService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Data
public class CameraStreamService implements ICameraStreamService {

    @Autowired
    private SRSProperties srsProperties;

    @Autowired
    private ICameraService cameraService;

    private final Map<Long, Process> ffmpegProcesses = new ConcurrentHashMap<>();

    private final Map<Long, Object> cameraLocks = new ConcurrentHashMap<>();

    private static final int MAX_RETRY = 5;  // 最大重试次数

    private static final int INITIAL_DELAY = 1000; // 初始延迟1秒

    @Override
    public String getPlayUrl(Long cameraId) {
        Camera camera = cameraService.getById(cameraId);
        if (camera != null) {
            String streamKey = camera.getStreamKey();
            String flvUrl = srsProperties.getFlvPrefixUrl() + streamKey + ".flv";

            if (camera.getStreamStatus() != 1) {
                Object lock = cameraLocks.computeIfAbsent(cameraId, k -> new Object());

                synchronized (lock) {
                    if (camera.getStreamStatus() != 1) {
                        startRtspToRtmp(camera);
                        camera.setStreamStatus(1);
                        cameraService.updateById(camera);
                    }
                }
            }

            return flvUrl;
        }
        throw new RuntimeException("不存在的摄像头信息");
    }

    @Override
    public void stopPlay(Long cameraId) {
        Camera camera = cameraService.getById(cameraId);
        if (camera != null) {
            Process process = ffmpegProcesses.remove(cameraId);
            if (process != null) {
                process.destroyForcibly();
                try {
                    process.waitFor();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }

            camera.setStreamStatus(0);
            cameraService.updateById(camera);
            cameraLocks.remove(cameraId);
        }
    }

    // 开始推流
    private void startRtspToRtmp(Camera camera) {
        String rtspUrl = cameraService.buildRTSPUrl(camera);

        List<String> command = new ArrayList<>();
        command.add("ffmpeg");
        command.add("-rtsp_transport");
        command.add("tcp");
        command.add("-i");
        command.add(rtspUrl);
        command.add("-c:v");
        command.add("h264");
        command.add("-preset");
        command.add("ultrafast");
        command.add("-b:v");
        command.add("1500k");
        // 添加关键参数：自动重连 RTSP
        command.add("-rtsp_flags");
        command.add("prefer_tcp");
        command.add("-use_wallclock_as_timestamps");
        command.add("1");
        command.add("-f");
        command.add("flv");
        // 添加关键参数：出错自动重连 RTMP
        command.add("-flvflags");
        command.add("autobsf");
        command.add("-reconnect");
        command.add("1");
        command.add("-reconnect_at_eof");
        command.add("1");
        command.add("-reconnect_streamed");
        command.add("1");
        command.add("-reconnect_delay_max");
        command.add("5");
        command.add(srsProperties.getRtmpUrl() + camera.getStreamKey());

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.redirectErrorStream(true);
        processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);

        try {
            Process process = processBuilder.start();
            ffmpegProcesses.put(camera.getId(), process);

            // 重试监听
//            monitorProcessWithRetry(process, camera, 0);
        } catch (IOException e) {
            throw new RuntimeException("Failed to start FFmpeg for " + camera.getStreamKey(), e);
        }
    }

//    private void monitorProcessWithRetry(Process process, Camera camera, int retryCount) {
//        CompletableFuture.runAsync(() -> {
//            try {
//                int exitCode = process.waitFor();
//                log.info("FFmpeg process for {} exited with code {}", camera.getStreamKey(), exitCode);
//
//                ffmpegProcesses.remove(camera.getId());
//
//                // 检查是否是用户主动停止
//                Camera currentCamera = cameraService.getById(camera.getId());
//                if (currentCamera == null || currentCamera.getStreamStatus() != 1) {
//                    log.info("Stream for {} is already stopped, skipping restart", camera.getStreamKey());
//                    return;
//                }
//
//                // 判断是否达到最大重试次数
//                if (retryCount >= MAX_RETRY) {
//                    log.error("Max retry attempts ({}) reached. Giving up on camera: {}", MAX_RETRY, camera.getStreamKey());
//                    camera.setStreamStatus(0);
//                    cameraService.updateById(camera);
//                    // TODO: 发送告警通知
//                    return;
//                }
//
//                // 使用递归方式重试，并递增 retryCount
//                restartRtspToRtmpWithRetry(camera, retryCount);
//
//            } catch (InterruptedException e) {
//                Thread.currentThread().interrupt();
//                log.warn("Process monitoring was interrupted for camera: {}", camera.getStreamKey());
//            } catch (Exception e) {
//                log.error("Unexpected error monitoring FFmpeg for camera: {}", camera.getStreamKey(), e);
//            }
//        });
//    }

    /**
     * 带重试机制地重启推流（维护 retryCount）
     */
//    private void restartRtspToRtmpWithRetry(Camera camera, int retryCount) {
//        CompletableFuture.delayedExecutor((long) INITIAL_DELAY * (1L << retryCount), TimeUnit.MILLISECONDS)
//                .execute(() -> {
//                    // 再次检查是否已手动停止
//                    Camera currentCamera = cameraService.getById(camera.getId());
//                    if (currentCamera == null || currentCamera.getStreamStatus() != 1) {
//                        log.info("Stream for {} is stopped manually, skip retry #{}", camera.getStreamKey(), retryCount);
//                        return;
//                    }
//
//                    try {
//                        startRtspToRtmp(currentCamera);
//                        log.info("Successfully restarted stream for {} on retry #{}", currentCamera.getStreamKey(), retryCount);
//                    } catch (Exception e) {
//                        log.error("Failed to restart stream for {} on retry #{}", currentCamera.getStreamKey(), retryCount, e);
//
//                        if (retryCount + 1 >= MAX_RETRY) {
//                            log.error("Max retry attempts ({}) exhausted for camera: {}", MAX_RETRY, currentCamera.getStreamKey());
//                            currentCamera.setStreamStatus(0);
//                            cameraService.updateById(currentCamera);
//                            // TODO: 可触发告警通知
//                        } else {
//                            // 继续递归重试
//                            restartRtspToRtmpWithRetry(currentCamera, retryCount + 1);
//                        }
//                    }
//                });
//    }
}
